<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: huajie <banhuajie@163.com>
// +----------------------------------------------------------------------
namespace Admin\Model;

use Think\Model;
use Admin\Model\AuthGroupModel;

/**
 * 文档基础模型
 */
class DocumentModel extends Model {
	
	/* 自动验证规则 */
	protected $_validate = array (
			array (
					'name',
					'/^[a-zA-Z]\w{0,39}$/',
					'文档标识不合法',
					self::VALUE_VALIDATE,
					'regex',
					self::MODEL_BOTH 
			),
			array (
					'name',
					'checkName',
					'标识已经存在',
					self::VALUE_VALIDATE,
					'callback',
					self::MODEL_BOTH 
			),
			array (
					'title',
					'require',
					'标题不能为空',
					self::MUST_VALIDATE,
					'regex',
					self::MODEL_BOTH 
			),
			array (
					'title',
					'1,80',
					'标题长度不能超过80个字符',
					self::MUST_VALIDATE,
					'length',
					self::MODEL_BOTH 
			),
			array (
					'level',
					'/^[\d]+$/',
					'优先级只能填正整数',
					self::VALUE_VALIDATE,
					'regex',
					self::MODEL_BOTH 
			),
			array (
					'description',
					'1,140',
					'简介长度不能超过140个字符',
					self::VALUE_VALIDATE,
					'length',
					self::MODEL_BOTH 
			),
			array (
					'category_id',
					'require',
					'分类不能为空',
					self::MUST_VALIDATE,
					'regex',
					self::MODEL_INSERT 
			),
			array (
					'category_id',
					'require',
					'分类不能为空',
					self::EXISTS_VALIDATE,
					'regex',
					self::MODEL_UPDATE 
			),
			array (
					'category_id',
					'check_category',
					'该分类不允许发布内容',
					self::EXISTS_VALIDATE,
					'function',
					self::MODEL_UPDATE 
			),
			array (
					'category_id,type',
					'check_category',
					'内容类型不正确',
					self::MUST_VALIDATE,
					'function',
					self::MODEL_INSERT 
			),
			array (
					'model_id,pid,category_id',
					'check_category_model',
					'该分类没有绑定当前模型',
					self::MUST_VALIDATE,
					'function',
					self::MODEL_INSERT 
			) 
	);
	
	/* 自动完成规则 */
	protected $_auto = array (
			array (
					'uid',
					'is_login',
					self::MODEL_INSERT,
					'function' 
			),
			array (
					'title',
					'htmlspecialchars',
					self::MODEL_BOTH,
					'function' 
			),
			array (
					'description',
					'htmlspecialchars',
					self::MODEL_BOTH,
					'function' 
			),
			array (
					'root',
					'getRoot',
					self::MODEL_BOTH,
					'callback' 
			),
			array (
					'link_id',
					'getLink',
					self::MODEL_BOTH,
					'callback' 
			),
			array (
					'attach',
					0,
					self::MODEL_INSERT 
			),
			array (
					'view',
					0,
					self::MODEL_INSERT 
			),
			array (
					'comment',
					0,
					self::MODEL_INSERT 
			),
			array (
					'extend',
					0,
					self::MODEL_INSERT 
			),
			array (
					'create_time',
					'getCreateTime',
					self::MODEL_BOTH,
					'callback' 
			),
			array (
					'update_time',
					NOW_TIME,
					self::MODEL_BOTH 
			),
			array (
					'status',
					'getStatus',
					self::MODEL_BOTH,
					'callback' 
			),
			array (
					'position',
					'getPosition',
					self::MODEL_BOTH,
					'callback' 
			),
			array (
					'deadline',
					'strtotime',
					self::MODEL_BOTH,
					'function' 
			) 
	);
	
	/**
	 * 获取详情页数据
	 * 
	 * @param integer $id
	 *        	文档ID
	 * @return array 详细数据
	 */
	public function detail($id) {
		/* 获取基础数据 */
		$info = $this->field ( true )->find ( $id );
		if (! (is_array ( $info ) || 1 !== $info ['status'])) {
			$this->error = '文档被禁用或已删除！';
			return false;
		}
		
		/* 获取模型数据 */
		$logic = $this->logic ( $info ['model_id'] );
		$detail = $logic->detail ( $id ); // 获取指定ID的数据
		if (! $detail) {
			$this->error = $logic->getError ();
			return false;
		}
		$info = array_merge ( $info, $detail );
		
		return $info;
	}
	
	/**
	 * 新增或更新一个文档
	 * 
	 * @param array $data
	 *        	手动传入的数据
	 * @return boolean fasle 失败 ， int 成功 返回完整的数据
	 * @author huajie <banhuajie@163.com>
	 */
	public function update($data = null) {
		/* 检查文档类型是否符合要求 */
		$res = $this->checkDocumentType ( I ( 'type', 2 ), I ( 'pid' ) );
		if (! $res ['status']) {
			$this->error = $res ['info'];
			return false;
		}
		
		/* 获取数据对象 */
		$data = $this->token ( false )->create ( $data );
		if (empty ( $data )) {
			return false;
		}
		
		/* 添加或新增基础内容 */
		if (empty ( $data ['id'] )) { // 新增数据
			$id = $this->add (); // 添加基础内容
			if (! $id) {
				$this->error = '新增基础内容出错！';
				return false;
			}
		} else { // 更新数据
			$status = $this->save (); // 更新基础内容
			if (false === $status) {
				$this->error = '更新基础内容出错！';
				return false;
			}
		}
		
		/* 添加或新增扩展内容 */
		$logic = $this->logic ( $data ['model_id'] );
		$logic->checkModelAttr ( $data ['model_id'] );
		if (! $logic->update ( $id )) {
			if (isset ( $id )) { // 新增失败，删除基础数据
				$this->delete ( $id );
			}
			$this->error = $logic->getError ();
			return false;
		}
		
		hook ( 'documentSaveComplete', array (
				'model_id' => $data ['model_id'] 
		) );
		
		// 行为记录
		if ($id) {
			action_log ( 'add_document', 'document', $id, UID );
		}
		
		// 内容添加或更新完成
		return $data;
	}
	
	/**
	 * 获取数据状态
	 * 
	 * @return integer 数据状态
	 */
	protected function getStatus() {
		$id = I ( 'post.id' );
		if (empty ( $id )) { // 新增
			$cate = I ( 'post.category_id' );
			$check = M ( 'Category' )->getFieldById ( $cate, 'check' );
			$status = $check ? 2 : 1;
		} else { // 更新
			$status = $this->getFieldById ( $id, 'status' );
			// 编辑草稿改变状态
			if ($status == 3) {
				$status = 1;
			}
		}
		return $status;
	}
	
	/**
	 * 获取根节点id
	 * 
	 * @return integer 数据id
	 * @author huajie <banhuajie@163.com>
	 */
	protected function getRoot() {
		$pid = I ( 'post.pid' );
		if ($pid == 0) {
			return 0;
		}
		$p_root = $this->getFieldById ( $pid, 'root' );
		return $p_root == 0 ? $pid : $p_root;
	}
	
	/**
	 * 创建时间不写则取当前时间
	 * 
	 * @return int 时间戳
	 * @author huajie <banhuajie@163.com>
	 */
	protected function getCreateTime() {
		$create_time = I ( 'post.create_time' );
		return $create_time ? strtotime ( $create_time ) : NOW_TIME;
	}
	
	/**
	 * 获取扩展模型对象
	 * 
	 * @param integer $model
	 *        	模型编号
	 * @return object 模型对象
	 */
	private function logic($model) {
		$name = parse_name ( get_document_model ( $model, 'name' ), 1 );
		$class = is_file ( MODULE_PATH . 'Logic/' . $name . 'Logic' . EXT ) ? $name : 'Base';
		$class = MODULE_NAME . '\\Logic\\' . $class . 'Logic';
		return new $class ( $name );
	}
	
	/**
	 * 检查标识是否已存在(只需在同一根节点下不重复)
	 * 
	 * @param string $name        	
	 * @return true无重复，false已存在
	 * @author huajie <banhuajie@163.com>
	 */
	protected function checkName() {
		$name = I ( 'post.name' );
		$category_id = I ( 'post.category_id', 0 );
		$id = I ( 'post.id', 0 );
		
		$map = array (
				'name' => $name,
				'id' => array (
						'neq',
						$id 
				),
				'status' => array (
						'neq',
						- 1 
				) 
		);
		
		$category = get_category ( $category_id );
		if ($category ['pid'] == 0) {
			$map ['category_id'] = $category_id;
		} else {
			$parent = get_parent_category ( $category ['id'] );
			$root = array_shift ( $parent );
			$map ['category_id'] = array (
					'in',
					D ( "Category" )->getChildrenId ( $root ['id'] ) 
			);
		}
		
		$res = $this->where ( $map )->getField ( 'id' );
		if ($res) {
			return false;
		}
		return true;
	}
	
	/**
	 * 生成不重复的name标识
	 * 
	 * @author huajie <banhuajie@163.com>
	 */
	private function generateName() {
		$str = 'abcdefghijklmnopqrstuvwxyz0123456789'; // 源字符串
		$min = 10;
		$max = 39;
		$name = false;
		while ( true ) {
			$length = rand ( $min, $max ); // 生成的标识长度
			$name = substr ( str_shuffle ( substr ( $str, 0, 26 ) ), 0, 1 ); // 第一个字母
			$name .= substr ( str_shuffle ( $str ), 0, $length );
			// 检查是否已存在
			$res = $this->getFieldByName ( $name, 'id' );
			if (! $res) {
				break;
			}
		}
		return $name;
	}
	
	/**
	 * 生成推荐位的值
	 * 
	 * @return number 推荐位
	 * @author huajie <banhuajie@163.com>
	 */
	protected function getPosition() {
		$position = I ( 'post.position' );
		if (! is_array ( $position )) {
			return 0;
		} else {
			$pos = 0;
			foreach ( $position as $key => $value ) {
				$pos += $value; // 将各个推荐位的值相加
			}
			return $pos;
		}
	}
	
	/**
	 * 删除状态为-1的数据（包含扩展模型）
	 * 
	 * @return true 删除成功， false 删除失败
	 * @author huajie <banhuajie@163.com>
	 */
	public function remove() {
		// 查询假删除的基础数据
		if (is_administrator ()) {
			$map = array (
					'status' => - 1 
			);
		} else {
			$cate_ids = AuthGroupModel::getAuthCategories ( UID );
			$map = array (
					'status' => - 1,
					'category_id' => array (
							'IN',
							trim ( implode ( ',', $cate_ids ), ',' ) 
					) 
			);
		}
		$base_list = $this->where ( $map )->field ( 'id,model_id' )->select ();
		// 删除扩展模型数据
		$base_ids = array_column ( $base_list, 'id' );
		// 孤儿数据
		$orphan = get_stemma ( $base_ids, $this, 'id,model_id' );
		
		$all_list = array_merge ( $base_list, $orphan );
		foreach ( $all_list as $key => $value ) {
			$logic = $this->logic ( $value ['model_id'] );
			$logic->delete ( $value ['id'] );
		}
		
		// 删除基础数据
		$ids = array_merge ( $base_ids, ( array ) array_column ( $orphan, 'id' ) );
		if (! empty ( $ids )) {
			$res = $this->where ( array (
					'id' => array (
							'IN',
							trim ( implode ( ',', $ids ), ',' ) 
					) 
			) )->delete ();
		}
		
		return $res;
	}
	
	/**
	 * 获取链接id
	 * 
	 * @return int 链接对应的id
	 * @author huajie <banhuajie@163.com>
	 */
	protected function getLink() {
		$link = I ( 'post.link_id' );
		if (empty ( $link )) {
			return 0;
		} else if (is_numeric ( $link )) {
			return $link;
		}
		$res = D ( 'Url' )->update ( array (
				'url' => $link 
		) );
		return $res ['id'];
	}
	
	/**
	 * 保存为草稿
	 * 
	 * @return array 完整的数据， false 保存出错
	 * @author huajie <banhuajie@163.com>
	 */
	public function autoSave() {
		$post = I ( 'post.' );
		
		/* 检查文档类型是否符合要求 */
		$res = $this->checkDocumentType ( I ( 'type', 2 ), I ( 'pid' ) );
		if (! $res ['status']) {
			$this->error = $res ['info'];
			return false;
		}
		
		// 触发自动保存的字段
		$save_list = array (
				'name',
				'title',
				'description',
				'position',
				'link_id',
				'cover_id',
				'deadline',
				'create_time',
				'content' 
		);
		foreach ( $save_list as $value ) {
			if (! empty ( $post [$value] )) {
				$if_save = true;
				break;
			}
		}
		
		if (! $if_save) {
			$this->error = '您未填写任何内容';
			return false;
		}
		
		// 重置自动验证
		$this->_validate = array (
				array (
						'name',
						'/^[a-zA-Z]\w{0,39}$/',
						'文档标识不合法',
						self::VALUE_VALIDATE,
						'regex',
						self::MODEL_BOTH 
				),
				array (
						'name',
						'',
						'标识已经存在',
						self::VALUE_VALIDATE,
						'unique',
						self::MODEL_BOTH 
				),
				array (
						'title',
						'1,80',
						'标题长度不能超过80个字符',
						self::VALUE_VALIDATE,
						'length',
						self::MODEL_BOTH 
				),
				array (
						'description',
						'1,140',
						'简介长度不能超过140个字符',
						self::VALUE_VALIDATE,
						'length',
						self::MODEL_BOTH 
				),
				array (
						'category_id',
						'require',
						'分类不能为空',
						self::MUST_VALIDATE,
						'regex',
						self::MODEL_BOTH 
				),
				array (
						'category_id',
						'check_category',
						'该分类不允许发布内容',
						self::EXISTS_VALIDATE,
						'function',
						self::MODEL_UPDATE 
				),
				array (
						'category_id,type',
						'check_category',
						'内容类型不正确',
						self::MUST_VALIDATE,
						'function',
						self::MODEL_INSERT 
				),
				array (
						'model_id,pid,category_id',
						'check_catgory_model',
						'该分类没有绑定当前模型',
						self::MUST_VALIDATE,
						'function',
						self::MODEL_INSERT 
				),
				array (
						'deadline',
						'/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/',
						'日期格式不合法,请使用"年-月-日 时:分"格式,全部为数字',
						self::VALUE_VALIDATE,
						'regex',
						self::MODEL_BOTH 
				),
				array (
						'create_time',
						'/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/',
						'日期格式不合法,请使用"年-月-日 时:分"格式,全部为数字',
						self::VALUE_VALIDATE,
						'regex',
						self::MODEL_BOTH 
				) 
		);
		$this->_auto [] = array (
				'status',
				'3',
				self::MODEL_BOTH 
		);
		
		if (! ($data = $this->create ())) {
			return false;
		}
		
		/* 添加或新增基础内容 */
		if (empty ( $data ['id'] )) { // 新增数据
			$id = $this->add (); // 添加基础内容
			if (! $id) {
				$this->error = '新增基础内容出错！';
				return false;
			}
			$data ['id'] = $id;
		} else { // 更新数据
			$status = $this->save (); // 更新基础内容
			if (false === $status) {
				$this->error = '更新基础内容出错！';
				return false;
			}
		}
		
		/* 添加或新增扩展内容 */
		$logic = $this->logic ( $data ['model_id'] );
		if (! $logic->autoSave ( $id )) {
			if (isset ( $id )) { // 新增失败，删除基础数据
				$this->delete ( $id );
			}
			$this->error = $logic->getError ();
			return false;
		}
		
		// 内容添加或更新完成
		return $data;
	}
	
	/**
	 * 检查指定文档下面子文档的类型
	 * 
	 * @param intger $type
	 *        	子文档类型
	 * @param intger $pid
	 *        	父文档类型
	 * @return array 键值：status=>是否允许（0,1），'info'=>提示信息
	 * @author huajie <banhuajie@163.com>
	 */
	public function checkDocumentType($type = null, $pid = null) {
		$res = array (
				'status' => 1,
				'info' => '' 
		);
		if (empty ( $type )) {
			return array (
					'status' => 0,
					'info' => '文档类型不能为空' 
			);
		}
		if (empty ( $pid )) {
			return $res;
		}
		// 查询父文档的类型
		$ptype = is_numeric ( $pid ) ? $this->getFieldById ( $pid, 'type' ) : $this->getFieldByName ( $pid, 'type' );
		// 父文档为目录时
		switch ($ptype) {
			case 1 : // 目录
			case 2 : // 主题
				break;
			case 3 : // 段落
				return array (
						'status' => 0,
						'info' => '段落下面不允许再添加子内容' 
				);
			default :
				return array (
						'status' => 0,
						'info' => '父文档类型不正确' 
				);
		}
		return $res;
	}
}